package user

import (
	"encoding/json"
	"errors"
	"gitee.com/cooge/impush/core"
	"gitee.com/cooge/impush/message"
	"gitee.com/cooge/impush/user"
	"gitee.com/cooge/impush/util"
	"github.com/sirupsen/logrus"
	"net"
	"net/http"
	"time"
)

type HttpConn struct {
	*user.UserLite
	breakTime     *time.Time
	Deadline      int
	HttpConnWrite HttpConnWriteFunc
	HttpConnFlush HttpConnFlushFunc
}

type HttpConnWriteFunc func(data []byte) (int, error)

type HttpConnFlushFunc func()

func (hc *HttpConn) Close(userId string) error {
	hc.breakTime = util.GetNowTime()
	logrus.Debug(hc.UserId, "断开连接", hc.breakTime)
	return hc.UserTCPConn.Close()
}
func (hc *HttpConn) IsBreak() bool {
	return hc.breakTime != nil
}

func (hc *HttpConn) IsTimeOut() bool {
	if hc.breakTime == nil {
		return false
	}
	return hc.breakTime.Add(time.Duration(hc.Deadline) * time.Second).Before(time.Now())
}

func (hc *HttpConn) SendMessages(msgs []*message.Message) (int, error) {
	data_ := make([]interface{}, 0)
	for _, v := range msgs {
		dat := make(map[string]interface{})
		dat[message.FROM] = v.Heads.Get(message.FROM)
		dat[message.BODY] = string(v.Body)
		data_ = append(data_, dat)
	}
	data, err := json.Marshal(&data_)
	if err == nil {
		return hc.HttpConnWrite(data)
	}
	return 0, errors.New(message.FAIL)
}

func (hc *HttpConn) Flush() {
	hc.HttpConnFlush()
}

func (hc *HttpConn) SendMessage(msg *message.Message) (int, error) {

	if hc.IsTimeOut() {
		return 0, errors.New(message.NO_USER)
	}

	if IsMessgeCache(hc.UserId, msg) {
		return 0, nil
	}

	dat := make(map[string]interface{})
	dat[message.FROM] = msg.Heads.Get(message.FROM)
	dat[message.BODY] = string(msg.Body)
	data, err := json.Marshal(&[1]map[string]interface{}{dat})
	if err == nil {
		return hc.HttpConnWrite(data)
	}
	return 0, nil
}

func (hc *HttpConn) Add() {
	ius := core.GetUser(hc.UserId)
	if ius != nil {
		das := ius.GetAllArray()
		core.AddUser(hc.UserId, hc)
		for _, v := range das {
			vv, ok := v.(*HttpConn)
			if ok {
				if vv.IsBreak() {
					core.DeleteUser(hc.UserId, vv)
				}
			}
		}
	} else {
		core.AddUser(hc.UserId, hc)
	}
}

type HttpUser interface {
	Flush()
	SendMessages([]*message.Message) (int, error)
	GetUserId() string
	Start(int, int, string, CallNewConnFunc)
	IsBreak() bool
}

type CallNewConnFunc func(HttpUser) bool

type CallDealRequestFunc func(http.ResponseWriter, *http.Request) (bool, net.Conn, string)

func CallNewConn(user HttpUser) bool {
	data := GetMessageCache(user.GetUserId())
	if data != nil && len(data) > 0 {
		_, err := user.SendMessages(data)
		if err == nil {
			return true
		}
	}
	return false
}
func CallDealRequest(w http.ResponseWriter, r *http.Request) (bool, net.Conn, string) {
	return preDeal(w, r)
}

func preDeal(w http.ResponseWriter, r *http.Request) (bool, net.Conn, string) {
	f := r.FormValue("f")
	id := r.FormValue("id")
	if len(id) == 0 {
		h := w.Header()
		h.Add("Access-Control-Allow-Origin", "*")
		w.WriteHeader(404)
		w.Write([]byte(`id can't null`))
	} else if len(f) > 0 {
		h := w.Header()
		h.Add("Access-Control-Allow-Origin", "*")
		w.Write([]byte(`[]`))
	} else {
		data := GetMessageCache(id)
		if data != nil && len(data) > 0 {
			h := w.Header()
			h.Add("Access-Control-Allow-Origin", "*")
			data_ := make([]interface{}, 0)
			for _, dat := range data {
				mdat := make(map[string]interface{})
				mdat[message.FROM] = dat.Heads.Get(message.FROM)
				mdat[message.BODY] = string(dat.Body)
				data_ = append(data_, mdat)
			}
			data, err := json.Marshal(&data_)
			if err == nil {
				w.Write(data)
			} else {
				w.Write([]byte{})
			}
		} else {
			h, ok := w.(http.Hijacker)
			if ok {
				netConn, _, err := h.Hijack()
				if err == nil {
					nc, ok := netConn.(net.Conn)
					if ok {
						return ok, nc, id
					} else {
						netConn.Close()
					}
				} else {
					w.Write([]byte(err.Error()))
				}
			} else {
				w.Write([]byte(message.FAIL))
			}
		}
	}
	return false, nil, ""
}
